﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Net;
using System.IO;
using System.Text;
using Urs.Core.Infrastructure;
using Urs.Services.Logging;

namespace tenpayApp
{
    public class WxPayApi
    {
        /**
        *    
        * 查询订单
        * @param WxPayData inputObj 提交给查询订单API的参数
        * @param int timeOut 超时时间
        * @throws Exception
        * @return 成功时返回订单查询结果，其他抛异常
        */
        public static WxPayData OrderQuery(WxPayData inputObj, string appId, string appKey, string partner, int timeOut = 6)
        {
            string url = "https://api.mch.weixin.qq.com/pay/orderquery";
            //检测必填参数
            if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
            {
                throw new Exception("订单查询接口中，out_trade_no、transaction_id至少填一个！");
            }

            inputObj.SetValue("appid", appId);//公众账号ID
            inputObj.SetValue("mch_id", partner);//商户号
            inputObj.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
            inputObj.SetValue("sign", inputObj.MakeSign());//签名

            string xml = inputObj.ToXml();

            string response = HttpHelper.GetResponse(url, xml, null, null);//调用HTTP通信接口提交数据
          
            //将xml格式的数据转化为对象以返回
            WxPayData result = new WxPayData(appKey);
            result.FromXml(response);

            return result;
        }


        /**
        * 
        * 撤销订单API接口
        * @param WxPayData inputObj 提交给撤销订单API接口的参数，out_trade_no和transaction_id必填一个
        * @param int timeOut 接口超时时间
        * @throws Exception
        * @return 成功时返回API调用结果，其他抛异常
        */
        public static WxPayData Reverse(WxPayData inputObj, string appId, string appKey, string partner, int timeOut = 6)
        {
            string url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
            //检测必填参数
            if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
            {
                throw new Exception("撤销订单API接口中，参数out_trade_no和transaction_id必须填写一个！");
            }

            inputObj.SetValue("appid", appId);//公众账号ID
            inputObj.SetValue("mch_id", partner);//商户号
            inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
            inputObj.SetValue("sign", inputObj.MakeSign());//签名
            string xml = inputObj.ToXml();

            var start = DateTime.Now;//请求开始时间

            string response = HttpHelper.GetResponse(url, xml, null, null);


            WxPayData result = new WxPayData(appKey);
            result.FromXml(response);

            return result;
        }


        /**
        * 
        * 申请退款
        * @param WxPayData inputObj 提交给申请退款API的参数
        * @param int timeOut 超时时间
        * @throws Exception
        * @return 成功时返回接口调用结果，其他抛异常
        */
        public static WxPayData Refund(WxPayData inputObj, string appId, string appKey, string partner, int timeOut = 6)
        {
            string url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
            //检测必填参数
            if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
            {
                throw new Exception("退款申请接口中，out_trade_no、transaction_id至少填一个！");
            }
            else if (!inputObj.IsSet("out_refund_no"))
            {
                throw new Exception("退款申请接口中，缺少必填参数out_refund_no！");
            }
            else if (!inputObj.IsSet("total_fee"))
            {
                throw new Exception("退款申请接口中，缺少必填参数total_fee！");
            }
            else if (!inputObj.IsSet("refund_fee"))
            {
                throw new Exception("退款申请接口中，缺少必填参数refund_fee！");
            }
            else if (!inputObj.IsSet("op_user_id"))
            {
                throw new Exception("退款申请接口中，缺少必填参数op_user_id！");
            }

            inputObj.SetValue("appid", appId);//公众账号ID
            inputObj.SetValue("mch_id", partner);//商户号
            inputObj.SetValue("nonce_str", Guid.NewGuid().ToString().Replace("-", ""));//随机字符串
            inputObj.SetValue("sign", inputObj.MakeSign());//签名
            
            string xml = inputObj.ToXml();

            string response = HttpHelper.GetResponse(url, xml, null, null);//调用HTTP通信接口提交数据到API
           
            //将xml格式的结果转换为对象以返回
            WxPayData result = new WxPayData(appKey);
            result.FromXml(response);

            return result;
        }


        /**
	    * 
	    * 查询退款
	    * 提交退款申请后，通过该接口查询退款状态。退款有一定延时，
	    * 用零钱支付的退款20分钟内到账，银行卡支付的退款3个工作日后重新查询退款状态。
	    * out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个
	    * @param WxPayData inputObj 提交给查询退款API的参数
	    * @param int timeOut 接口超时时间
	    * @throws Exception
	    * @return 成功时返回，其他抛异常
	    */
        public static WxPayData RefundQuery(WxPayData inputObj, string appId, string appKey, string partner, int timeOut = 6)
	    {
		    string url = "https://api.mch.weixin.qq.com/pay/refundquery";
		    //检测必填参数
		    if(!inputObj.IsSet("out_refund_no") && !inputObj.IsSet("out_trade_no") &&
			    !inputObj.IsSet("transaction_id") && !inputObj.IsSet("refund_id"))
            {
			    throw new Exception("退款查询接口中，out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个！");
		    }

            inputObj.SetValue("appid", appId);//公众账号ID
            inputObj.SetValue("mch_id", partner);//商户号
		    inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串
		    inputObj.SetValue("sign",inputObj.MakeSign());//签名

		    string xml = inputObj.ToXml();
		
            string response = HttpHelper.GetResponse(url, xml, null, null);//调用HTTP通信接口以提交数据到API
          
            //将xml格式的结果转换为对象以返回
            WxPayData result = new WxPayData(appKey);
            result.FromXml(response);
		
		    return result;
	    }


        /**
        * 下载对账单
        * @param WxPayData inputObj 提交给下载对账单API的参数
        * @param int timeOut 接口超时时间
        * @throws Exception
        * @return 成功时返回，其他抛异常
        */
        public static WxPayData DownloadBill(WxPayData inputObj, string appId, string appKey, string partner, int timeOut = 6)
        {
            string url = "https://api.mch.weixin.qq.com/pay/downloadbill";
            //检测必填参数
            if (!inputObj.IsSet("bill_date"))
            {
                throw new Exception("对账单接口中，缺少必填参数bill_date！");
            }

            inputObj.SetValue("appid", appId);//公众账号ID
            inputObj.SetValue("mch_id", partner);//商户号
            inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
            inputObj.SetValue("sign", inputObj.MakeSign());//签名

            string xml = inputObj.ToXml();

            string response = HttpHelper.GetResponse(url, xml, null, null);//调用HTTP通信接口以提交数据到API

            WxPayData result = new WxPayData(appKey);
            //若接口调用失败会返回xml格式的结果
            if (response.Substring(0, 5) == "<xml>")
            {
                result.FromXml(response);
            }
            //接口调用成功则返回非xml格式的数据
            else
                result.SetValue("result", response);

            return result;
        }


        /**
	    * 
	    * 转换短链接
	    * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX)，
	    * 减小二维码数据量，提升扫描速度和精确度。
	    * @param WxPayData inputObj 提交给转换短连接API的参数
	    * @param int timeOut 接口超时时间
	    * @throws Exception
	    * @return 成功时返回，其他抛异常
	    */
        public static WxPayData ShortUrl(WxPayData inputObj, string appId, string appKey, string partner, int timeOut = 6)
	    {
		    string url = "https://api.mch.weixin.qq.com/tools/shorturl";
		    //检测必填参数
		    if(!inputObj.IsSet("long_url"))
            {
			    throw new Exception("需要转换的URL，签名用原串，传输需URL encode！");
		    }

            inputObj.SetValue("appid", appId);//公众账号ID
            inputObj.SetValue("mch_id", partner);//商户号
		    inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串	
		    inputObj.SetValue("sign",inputObj.MakeSign());//签名
		    string xml = inputObj.ToXml();
		
            string response = HttpHelper.GetResponse(url, xml, null, null);

            WxPayData result = new WxPayData(appKey);
            result.FromXml(response);
		
		    return result;
	    }


        /**
        * 
        * 统一下单
        * @param WxPaydata inputObj 提交给统一下单API的参数
        * @param int timeOut 超时时间
        * @throws Exception
        * @return 成功时返回，其他抛异常
        */
        public static WxPayData UnifiedOrder(WxPayData inputObj, string appId, string appKey, string partner,string notifyUrl, string spbill_create_ip,out string initdataRequest)
        {
            string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            //检测必填参数
            if (!inputObj.IsSet("out_trade_no"))
            {
                throw new Exception("缺少统一支付接口必填参数out_trade_no！");
            }
            else if (!inputObj.IsSet("body"))
            {
                throw new Exception("缺少统一支付接口必填参数body！");
            }
            else if (!inputObj.IsSet("total_fee"))
            {
                throw new Exception("缺少统一支付接口必填参数total_fee！");
            }
            else if (!inputObj.IsSet("trade_type"))
            {
                throw new Exception("缺少统一支付接口必填参数trade_type！");
            }

            //关联参数
            if (inputObj.GetValue("trade_type").ToString() == "JSAPI" && !inputObj.IsSet("openid"))
            {
                throw new Exception("统一支付接口中，缺少必填参数openid！trade_type为JSAPI时，openid为必填参数！");
            }
            if (inputObj.GetValue("trade_type").ToString() == "NATIVE" && !inputObj.IsSet("goods_id"))
            {
                throw new Exception("统一支付接口中，缺少必填参数goods_id！trade_type为JSAPI时，goods_id为必填参数！");
            }

            //异步通知url未设置，则使用配置文件中的url
            if (!inputObj.IsSet("notify_url"))
            {
                inputObj.SetValue("notify_url", notifyUrl);//异步通知url
            }
            inputObj.SetValue("appid", appId);//公众账号ID
            inputObj.SetValue("mch_id", partner);//商户号
            inputObj.SetValue("spbill_create_ip", spbill_create_ip);//终端ip	  	    
            inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
            //签名
            var sign= inputObj.MakeSign();
            inputObj.SetValue("sign", sign);
            string xml = inputObj.ToXml();

            initdataRequest = xml;

            string response = HttpHelper.GetResponse(url, xml, null, null);

            WxPayData result = new WxPayData(appKey);
            result.FromXml(response);

            return result;
        }

 
        /**
	    * 
	    * 关闭订单
	    * @param WxPayData inputObj 提交给关闭订单API的参数
	    * @param int timeOut 接口超时时间
	    * @throws Exception
	    * @return 成功时返回，其他抛异常
	    */
        public static WxPayData CloseOrder(WxPayData inputObj, string appId, string appKey, string partner, int timeOut = 6)
	    {
		    string url = "https://api.mch.weixin.qq.com/pay/closeorder";
		    //检测必填参数
		    if(!inputObj.IsSet("out_trade_no"))
            {
			    throw new Exception("关闭订单接口中，out_trade_no必填！");
		    }

            inputObj.SetValue("appid", appId);//公众账号ID
            inputObj.SetValue("mch_id", partner);//商户号
		    inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串		
		    inputObj.SetValue("sign",inputObj.MakeSign());//签名
		    string xml = inputObj.ToXml();
		
            string response = HttpHelper.GetResponse(url, xml, null, null);

            WxPayData result = new WxPayData(appKey);
            result.FromXml(response);

		    return result;
	    }

        /**
        * 生成时间戳，标准北京时间，时区为东八区，自1970年1月1日 0点0分0秒以来的秒数
         * @return 时间戳
        */
        public static string GenerateTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        /**
        * 生成随机串，随机串包含字母或数字
        * @return 随机串
        */
        public static string GenerateNonceStr()
        {
            return Guid.NewGuid().ToString().Replace("-", "");
        }
    }
}